package com.rulestech.framework.unittest;

import static org.junit.Assert.assertEquals;

import java.util.ArrayList;
import java.util.Collection;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

/**
 * This base class setup the foundation for the data driven unit test. The idea is that the sub class only needs to specify for to calculate the actual result and leave everything else to the base class.
 * 
 * @author seanxsu
 *
 */

@RunWith(Parameterized.class)
public abstract class DataDrivenBaseTest {

	private Object input;
	private Object output;
	private Object actualOutput;

	/**
	 * Format the collection of DataDrivenTestCase to what the framework recognizes.
	 * @param testcases
	 * @return
	 */
	protected static Collection<Object[]> format(Collection<DataDrivenTestCase> testcases){
		Collection <Object[]>  result = new ArrayList<Object[]>();
		for (DataDrivenTestCase testcase : testcases){
			result.add(new Object[] {testcase.getInput(), testcase.getOutput()});
		}
		return result;
	}

	/**
	 * Users of the framework must implement this method so that the actual result can be calculated and returned here.
	 * The returned value will be used to compare the expected result.
	 * 
	 * @param input input object based which the output will be calculated.
	 * @return the calculated output
	 * @throws Exception any possible run time exceptions.
	 */
	protected abstract Object computeActualResult(Object input) throws Exception;

	public DataDrivenBaseTest(Object input, Object output) throws Exception {
		super();
		this.input = input;
		this.output = output;
		this.actualOutput = computeActualResult(input);
	}
	
	

	public Object getInput() {
		return input;
	}

	public Object getOutput() {
		return output;
	}

	@Test
	public void testOutputMatchExptected() {
		assertEquals("Actual output does not match the exptected output: \nExpected output:\n" + output + "\nActual output:\n" + actualOutput + "\n", output, actualOutput);
	}

}
